import decimal
from datetime import datetime
from enum import Enum
from typing import Dict, Any

from flask_sqlalchemy import SQLAlchemy
from sqlalchemy import DateTime, inspect, JSON
from sqlalchemy.orm import DeclarativeBase, scoped_session, Session, mapped_column, Mapped, Query
from sqlalchemy.orm.attributes import flag_modified

from application.util.TimeUtil import now_format_datetime


def paginate_query(query: Query, page: int = 1, per_page: int = 10):
    """
    对 SQLAlchemy 查询对象进行分页处理。

    :param query: SQLAlchemy 查询对象
    :param page: 当前页码，默认为 1
    :param per_page: 每页显示的记录数，默认为 10
    :return: 分页后的结果列表
    """
    if page < 1:
        page = 1
    if per_page < 1:
        per_page = 10

    offset = (page - 1) * per_page
    return query.limit(per_page).offset(offset).all(), query.count()


class BaseModel(DeclarativeBase):
    """
    模型基类
    """
    # 更新时间，默认为now_format_datetime生成，更新时为now_format_datetime生成
    update_datetime: Mapped[datetime] = mapped_column(DateTime, insert_default=now_format_datetime(),
                                                      onupdate=now_format_datetime(),
                                                      nullable=True, comment="更新时间")
    # 创建时间，默认为now_format_datetime生成的
    create_datetime: Mapped[datetime] = mapped_column(DateTime, insert_default=now_format_datetime(), nullable=True,
                                                      comment="创建时间")

    def to_dict(self, include=None, exclude=None):
        """
        转换为字典，可指定 include 或 exclude 列表。
        :param include: 指定仅返回的字段名列表
        :param exclude: 指定排除的字段名列表
        :return: dict
        """
        result = {}
        include = set(include) if include else None
        exclude = set(exclude) if exclude else set()

        for c in inspect(self).mapper.column_attrs:
            key = c.key
            if include is not None and key not in include:
                continue
            if key in exclude:
                continue
            value = getattr(self, key)
            if isinstance(value, datetime):
                value = value.strftime('%Y-%m-%d %H:%M:%S')
            if isinstance(value, decimal.Decimal):
                value = float(value)
            if isinstance(value, Enum):
                value = value.value
            result[key] = value
        return result

    @classmethod
    def get_by_id(cls, model_id: int):
        """
        根据id获取数据
        :param model_id: 数据id
        :return: 数据字典
        """
        return cls.query.get(model_id)

    def update_orm_object(self, data: Dict[str, Any], update_null=False):
        for key, value in data.items():
            if hasattr(self, key):
                if value is None and not update_null:
                    continue
                setattr(self, key, value)
                if isinstance(getattr(self, key), JSON):
                    flag_modified(self, key)


# 初始化SQLAlchemy
mysql_db: SQLAlchemy = SQLAlchemy(model_class=BaseModel)
# 获得会话
mysql_session: scoped_session[Session] = mysql_db.session
